#include "fxcc/core/platform/glfw/App.h"
#include "fxcc/core/platform/common/Input.h"

using namespace fxcc::platform::glfw;

fxcc::platform::glfw::App::App(const common::App::Desc& desc)
    : common::App(desc) 
{
	m_HintMap = 
	{
		{ GLFW_CONTEXT_VERSION_MAJOR, 4},
		{ GLFW_CONTEXT_VERSION_MINOR, 3},
		{ GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE},
		{ GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE },

	};
};

bool App::Init()
{
	if (!InitGlfw())
	{
		ztclog::warn("failed init window");
		return false;
	}
	return true;
};

bool fxcc::platform::glfw::App::InitGlfw()
{
	if (!glfwInit())
	{
		ztclog::warn("failed create glfw window");
		return false;
	}
	for (const auto& hint : m_HintMap)
	{
		glfwWindowHint(hint.first, hint.second);
	}

	glm::ivec2 wndPos = m_Desc.GetGflwPos();
	glm::ivec2 wndSize = m_Desc.GetGflwSize();

	m_GlfwWindow = glfwCreateWindow(wndSize.x, wndSize.y, m_Desc.m_Title.c_str(), nullptr, nullptr);
	if (!m_GlfwWindow) {
		ztclog::warn("failed create window");
		glfwTerminate();
		return false;
	}

	glfwMakeContextCurrent(m_GlfwWindow);

	glfwSetWindowSize(m_GlfwWindow, wndSize.x, wndSize.y);
	glfwSetWindowPos(m_GlfwWindow, wndPos.x, wndPos.y);
	glfwSetWindowTitle(m_GlfwWindow, m_Desc.m_Title.c_str());

	if (m_Desc.m_Iconify)
	{
		glfwIconifyWindow(m_GlfwWindow);
	}

	glfwSwapInterval(m_Desc.m_Interval);

	CallBacks::Register(this);

	GetJoyStickDevices();

	m_GlfwlTimer.Start();

	return true;
}


void fxcc::platform::glfw::App::GetJoyStickDevices()
{
	for (int i = 0; i < GLFW_JOYSTICK_LAST; ++i)
	{
		if (glfwJoystickPresent(i))
		{
			m_Input.JoysticCallback(i, 1, glfwGetJoystickName(i));
		}
	}
}

namespace
{

	std::vector<unsigned char> m_lastJoybuttons;
	std::vector<unsigned char> m_JoyButtons;
	
	static void SetCharBuffer(std::vector<unsigned char>& btns, int num,const unsigned char* source)
	{
		if (btns.size() != num)
		{
			btns.resize(num);
		}
		memcpy(&btns[0], source, num * sizeof(unsigned char));
	}
};

void fxcc::platform::glfw::App::OnDestroy()
{
	glfwTerminate();
	glfwDestroyWindow(m_GlfwWindow);

}

void App::OnUpdate()
{
	OnJoystick();
	m_GlfwlTimer.Tick();
}

void fxcc::platform::glfw::App::OnJoystick()
{
	std::vector<int> joyDecvices = m_Input.GetJoystickNos();
	for (const auto& jId : joyDecvices)
	{
		int count;
		const unsigned char* buttons = glfwGetJoystickButtons(jId, &count);
		//m_lastJoybuttons.resize();
		SetCharBuffer(m_JoyButtons, count, buttons);
		for (int i = 0; i < count; i++)
		{
			if (m_JoyButtons.size() > i && m_lastJoybuttons.size() > 0)
			{
				if (m_JoyButtons[i] != m_lastJoybuttons[i])
				{
					//ztclog::debug("down or up");
					//if (m_JoyButtons[i])
					//{
					//	ztclog::debug("btn %d down ",i);
					//}
					//else
					//{
					//	ztclog::debug("btn %d up ", i);
					//}
					if (i >= 0 && i <= 9)
					{
						// Button down
						m_Input.SetJoystickButton(jId, CallBacks::m_JoystickMap[i], ActionType(m_JoyButtons[i]));
					}
					else
					{
						glm::ivec2 hat(0);
						if (i == 10)
						{
							hat.y = 1;
						}
						if (i == 11)
						{
							hat.x = 1;
						}
						if (i == 12)
						{
							hat.y = -1;
						}
						if (i == 13) {
							hat.x = -1;
						}
						m_Input.SetJoystickHat(jId, hat.x, hat.y);
					}
				}
			}
		}
		SetCharBuffer(m_lastJoybuttons, count, buttons);


		int axesCount;
		const float* axes = glfwGetJoystickAxes(jId, &axesCount);

		for (int i = 0; i < axesCount; i++)
		{
			m_Input.SetJoystickAxes(jId, axes[i], axesCount);
		}
	}
	
};


void App::OnFramebuffersize(int w, int h)
{
    m_Desc.m_Size.x = w; 
    m_Desc.m_Size.y = h;
}

void App::OnWindowPos(int x, int y)
{
    m_Desc.m_Pos.x = x;
    m_Desc.m_Pos.y;
}

void App::OnFocus(int e) {
    m_Desc.m_Focused = e;
}

void fxcc::platform::glfw::App::OnIconify(int e)
{
    m_Desc.m_Iconify = e;
};

void App::OnClose()
{
    ztclog::debug("Current window %s Close", m_Desc.m_Title.c_str());
}
void App::OnRefresh()
{
    ztclog::debug("Current window %s Refresh", m_Desc.m_Title.c_str());
}

void fxcc::platform::glfw::App::OnMonitor(int e)
{
	ztclog::debug("Current window %s Monitor %d", m_Desc.m_Title.c_str()), e;

}
